module Cool
  if not const_defined?(:DEFAULT_TABLE_FEATURES)
    DEFAULT_TABLE_FEATURES = {:pagination => true, :sort => true, :ajax => false}
  end
  
  if not const_defined?(:CLASSIC_COLUMNS)
    CLASSIC_COLUMNS = {
      :$show => proc{| view,table_id,options |
        column = Table.init_classic_column(view,table_id,options) do |column,singular_path|
          column.ruby_block = proc{|item| view.link_to 'Show', view.send(singular_path,item) }
        end
      },
      :$edit => proc{| view,table_id,options |
        column = Table.init_classic_column(view,table_id,options) do |column,singular_path|
          column.ruby_block = proc{|item| view.link_to 'Edit', view.send('edit_' + singular_path,item) }
        end
      },
      :$destroy => proc{| view,table_id,options |
        column = Table.init_classic_column(view,table_id,options) do |column,singular_path|
          column.ruby_block = proc do |item| 
            view.link_to 'Destroy', view.send(singular_path,item),
            :confirm => 'Are you sure?', :method => :delete 
          end
        end
        
      }
    }
  end
  
  include ::ActionView::Helpers::CaptureHelper
  class Column
    attr_accessor :name,:label,:options,:ruby_block,:erb_block
    def initialize(view)
      @view = view
    end  
    
    def render_header(sort)
      sort_by = @view.params[:sort_by]
      order = @view.params[:order]
      _label = (@label || @name.to_s.humanize)
      url = @view.request.request_uri
     if not sort
        s = @view.content_tag('td',_label, :class=>'table_for_header')
     else
        if url.include?("sort_by") and url.include?("order")
          if _label == sort_by
              o = order == 'asc' ? 'desc' : 'asc'
              s = @view.content_tag('td',"<a href='" + url.sub(/sort_by=\w*/, "sort_by=" + _label.gsub(" ", "_")).sub(/order=\w*/, "order=" + o) + "'>" + _label + "</a>", :class=>'table_for_header ' + order)
          else
              s = @view.content_tag('td',"<a href='" + url.sub(/sort_by=\w*/, "sort_by=" + _label.gsub(" ", "_")).sub(/order=\w*/, "order=asc") + "'>" + _label + "</a>", :class=>'table_for_header')
          end
        elsif url.include?('?')
            s = @view.content_tag('td',"<a href='" + url + "&sort_by=" + _label.gsub(" ", "_") + "&order=asc'>" + _label + "</a>", :class=>'table_for_header')
        else
            s = @view.content_tag('td',"<a href='" + url + "?sort_by=" + _label.gsub(" ", "_") + "&order=asc'>" + _label + "</a>", :class=>'table_for_header')
        end
     end
      s
    end
    
    def render_body(*args)
      if @ruby_block
        column_html = @ruby_block.call(*args)
      elsif @erb_block
        column_html = @view.capture(*args,&@erb_block).to_s
      else
        model = args[0]
        column_html = CGI.escapeHTML(model.send(@name).to_s)
       if column_html == 'true'
         column_html = 'yes'
       elsif column_html == 'false'
        column_html = 'no'
       end
      end
      html_options = options && options[:col_options]
      @view.content_tag('td',column_html,html_options)
    end
  end
  
  class Table
    def self.init_classic_column(view,table_id,options=nil)
      column = Column.new(view)
      column.name = nil
      column.label = options && options[:label]
      column.options = options
      resource = table_id
      singular_path = "#{resource.to_s.singularize}_path"
      yield column,singular_path
      column
    end
    
    def build_classic_column(classic_column_key,options=nil)
      CLASSIC_COLUMNS[classic_column_key].call(@view,@table_id,options)
    end
    
    attr_accessor :table_id,:options
    
    def initialize(view,table_id,data_list,options={})
      @view = view
      @table_id = table_id
      @data_list = data_list
      @options = DEFAULT_TABLE_FEATURES.merge(options)
      @columns = []
    end
    
    def columns_count
      @columns.size
    end
    
    def column(column_name=nil,options=nil,&block)
      if column_name.to_s.starts_with?("$")
        column = self.build_classic_column(column_name,options)
      else
        options ||= {}
        column = Column.new(@view)
        column.name = column_name
        column.options = options
        column.ruby_block = block
        column.label = options[:label]
      end
      @columns << column
      column
    end
    
    alias_method :ruby_column,:column
    
    def erb_column(*arguments,&block)
      col = column(*arguments,&block)
      col.ruby_block = nil
      col.erb_block = block
    end
    
    def columns(*args)
      for col in args
        self.column(col)
      end
    end
    
    
    def render
      table_attrs = {:id => @table_id, :class=>'table_for'}
      table_html = @view.content_tag('table',render_header(@options[:sort])+render_body,table_attrs)
      pagination = ""
      if @options[:pagination]
        pagination = render_pagination.to_s
      end
      ajax = ""
      if @options[:ajax]
        ajax = render_ajax_pagination_and_sort
      end
      return "<div id='#{@table_id}_table' class='table_for_container'>" + table_html + pagination + ajax + "</div>"
    end
    
    def render_header(sort)
      header_html = ""
      @columns.each_with_index do |column,index|
        header_html << column.render_header(sort)
      end
      s = @view.content_tag('thead',
        @view.content_tag('tr',header_html))
      s
    end
     
    def render_row(model,index)
      row_html = ""
      @columns.each do |column|
        row_html << column.render_body(model)
      end
      row_html
    end
    
    
    def render_body
      before_render_row,after_render_row = @options[:before_render_row],@options[:after_render_row]
      tbody = ""
      @data_list.each_with_index do |model,index|
        row_html = render_row(model,index)
        tr_class = (index % 2 == 0) ? 'even' : 'odd'
        if before_render_row
          tbody << before_render_row.call(model,index)
        end
       if @options[:row_options]
          tbody << @view.content_tag('tr',row_html,{'class'=>tr_class}.merge(@options[:row_options]))
        else
        tbody << @view.content_tag('tr',row_html,{'class'=>tr_class})
        end
        if after_render_row
          tbody << after_render_row.call(model,index)
       end
        
      end
      @view.content_tag('tbody',tbody)
    end
    
    def render_pagination
      @view.will_paginate(@data_list)
    end
        
    def render_ajax_pagination_and_sort
      script = <<-EOS
        bind_pagination_event();
        bind_sort_event();
      EOS
     @view.content_tag("script", script)
   end

  end
end